home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / internet / javnl004.zip / JAVNL004.TXT < prev   
Text File  |  1996-04-23  |  20KB  |  530 lines

  1. Issue #004
  2. April, 1996
  3.  
  4.  
  5. Contents:
  6.  
  7. Random Numbers in Java
  8. Comparing C/C++ with Java Part 4 - Templates
  9. Book Review
  10. Java Program Packaging Part 2 - Public/Private
  11. Performance - String Operations
  12.  
  13.  
  14. RANDOM NUMBERS IN JAVA
  15.  
  16. Random numbers are useful in many contexts in programming.  One common
  17. use is in games, and another is for testing program algorithms such as
  18. those used in searching or sorting.
  19.  
  20. Java has random number support in the library class java.util.Random.
  21. Basic use is:
  22.  
  23.         import java.util.*;
  24.  
  25.         Random rn = new Random();
  26.  
  27.         ...
  28.  
  29.         int r = rn.nextInt();           // 32-bit random number
  30.  
  31.         double d = rn.nextDouble();     // random value in range 0.0 - 1.0
  32.  
  33. The random number generation algorithm is based on the linear
  34. congruential method (see for example Chapter 3 in Volume 2 of Knuth's
  35. "Art of Computer Programming").  This method has a starting value (a
  36. "seed"), and each value of the sequence is generated from the last.
  37. Whether such a stream of random numbers are in fact truly random is an
  38. interesting question beyond the scope of this discussion.  If you're
  39. interested in that question you might consult Knuth's book.
  40.  
  41. If the default Random() constructor is used, the random number
  42. generator is seeded from the current time of day.  You can also
  43. specify your own seed:
  44.  
  45.         Random rn = new Random(1234);
  46.  
  47. to generate a repeatable sequence of random numbers.
  48.  
  49. To show how random numbers might be used, here is a class Test that
  50. will generate random numbers in a range using the rand() method, or
  51. generate random strings composed of characters 'a' ... 'z'.
  52.  
  53.         import java.util.*;
  54.  
  55.         public class Test {
  56.  
  57.                 private static Random rn = new Random();
  58.  
  59.                 private Test()
  60.                 {
  61.                 }
  62.  
  63.                 public static int rand(int lo, int hi)
  64.                 {
  65.                         int n = hi - lo + 1;
  66.                         int i = rn.nextInt() % n;
  67.                         if (i < 0)
  68.                                 i = -i;
  69.                         return lo + i;
  70.                 }
  71.  
  72.                 public static String randomstring(int lo, int hi)
  73.                 {
  74.                         int n = rand(lo, hi);
  75.                         byte b[] = new byte[n];
  76.                         for (int i = 0; i < n; i++)
  77.                                 b[i] = (byte)rand('a', 'z');
  78.                         return new String(b, 0);
  79.                 }
  80.  
  81.                 public static String randomstring()
  82.                 {
  83.                         return randomstring(5, 25);
  84.                 }
  85.         }
  86.  
  87. Actual random numbers are obtained using nextInt(), and then knocked
  88. down to the relevant range using the modulo ("%") operator.
  89.  
  90. Note that Test is simply a packaging vehicle with all of the methods
  91. as class methods ("static").  To obtain a random String of between 10
  92. and 40 characters, you would say:
  93.  
  94.         String s = Test.randomstring(10, 40);
  95.  
  96.  
  97. COMPARING C/C++ WITH JAVA PART 4 - TEMPLATES
  98.  
  99. Suppose that you have a vector of numbers or strings or other objects
  100. that you'd like to sort.  How would you do this?  One way is to devise
  101. a specialized sorting function unique to your program, that is, a
  102. function that simply sorts whatever vector is at hand.
  103.  
  104. This is fine but it's wasteful to have to repeatedly implement the
  105. same sorting algorithm for slightly differing situations across a
  106. variety of programs.  To help solve this problem, C has a standard
  107. library function that implements the Quicksort algorithm:
  108.  
  109.         void qsort(void* base, size_t n, size_t size,
  110.                 int (*cmp)(const void*, const void*));
  111.  
  112. The idea is that you pass in a pointer to the base of a data
  113. structure, along with the number of elements in the structure and the
  114. size of each.  You also pass in a function pointer.  The function is
  115. called with pairs of elements and it returns < 0, 0, or > 0 to specify
  116. ordering of the elements.  This approach is fairly low-level but works
  117. pretty well.  C++ also has access to qsort().
  118.  
  119. In C++ there is also the notion of function templates, a function that
  120. can be parameterized with a type parameter so that the same function
  121. skeleton can operate on different types.  For example, a simple sort
  122. might look like:
  123.  
  124.         template <class T> void sort(T vec[], int n)
  125.         {
  126.                 for (int i = 0; i < n - 1; i++) {
  127.                         for (int j = i + 1; j < n; j++) {
  128.                                 if (vec[i] > vec[j]) {
  129.                                         T t = vec[i];
  130.                                         vec[i] = vec[j];
  131.                                         vec[j] = t;
  132.                                 }
  133.                         }
  134.                 }
  135.         }
  136.  
  137. This will work for all numeric types and for any class types for which
  138. relational operators, initialization, and assignment are defined.
  139. Note that the sorting algorithm in this example has running time
  140. proportional to N**2 and we would want to use a more efficient one in
  141. production code.
  142.  
  143. Java does not have templates or user-visible pointers or sizeof(), so
  144. the above approaches will not work.  One possible alternative would be
  145. to exploit the idea of all Java class types being derived from a
  146. single Object base.  This means that one can have a vector of Object
  147. references containing actual Objects, Strings, numerics (using
  148. wrappers), and so on.  A reference to any object of a derived class
  149. type can be assigned to an Object reference.  For example, I can say:
  150.  
  151.         Object vec[] = new Object[10];
  152.  
  153.         for (int i = 0; i < 10; i++)
  154.                 vec[i] = new Integer(i);
  155.  
  156. to represent the numbers 0-9 in a vector.  The Vector class in the
  157. Java library supports this type of usage.
  158.  
  159. But representing numbers or Strings or other entities in this way
  160. doesn't solve the sorting problem.  Object is the base of all class
  161. types, and it contains an equals() method for comparing two objects
  162. for equality, but there is no method for determining the ordering of
  163. two objects.  For example, given two slots of a Vector, containing
  164. references to the objects "Integer(37)" and "Integer(47)", there is no
  165. direct way of ordering these.
  166.  
  167. What can be done is to interrogate the actual type of the object and
  168. obtain its value indirectly:
  169.  
  170.         if (vec[5] instanceof Integer)
  171.                 value = ((Integer)vec[5]).intValue();
  172.  
  173. "instanceof" is an operator that returns true if the object on its
  174. left side is an instance of the class found on the right side.
  175.  
  176. Using a technique like this, it would be possible to write a method
  177. that accepted a vector of Object references, and sort that vector by
  178. querying and extracting the numbers in it and exchanging their
  179. references in the slots of the vector.  The Object wrapper approach is
  180. quite flexible and general but at the expense of speed and space.
  181.  
  182. Another approach is to special-case common types like int and String,
  183. and add an interface with a name like Orderable for ordering arbitrary
  184. class type objects.  A class that implements Orderable is guaranteed
  185. to define a method compareTo() that will order object instances.  The
  186. types int, String, Orderable, and Object can be supported within a
  187. single List class using overloaded methods for adding new elements to
  188. the list.  Actual elements such as ints can be directly represented
  189. using an int[] vector that grows as new elements are added, and
  190. operations like binary searching, sorting, and binary trees can be
  191. implemented efficiently.  This approach is ugly on the inside but
  192. presents a fairly clean interface to the user.
  193.  
  194. It is possible to simulate some of the features of C++ templates by
  195. using macros such as #define in C/C++, or macro processing tools like
  196. the tool "m4" available in UNIX.  Java has no macro processing, though
  197. one could add auxiliary tools if desired.
  198.  
  199. Are templates very important?  This is a hard question to answer.  In
  200. C++, they are used heavily, for example in STL, the Standard Template
  201. Library.  In certain situations they solve a messy problem in an
  202. elegant way.  But C++ templates are also very complex and hard to
  203. implement and master, and so it's possible to debate the issue without
  204. reaching any definite conclusions.  There's something to be said for
  205. simpler language features, even if the result is more verbose code.
  206.  
  207.  
  208. BOOK REVIEW
  209.  
  210. An excellent all-in-one volume on Java is the book "Java in a
  211. Nutshell" by David Flanagan (O'Reilly & Associates, $15).  It's about
  212. 400 pages and covers both the language and libraries, with many
  213. examples and a comprehensive index.
  214.  
  215. The book has a description of each library class, such as String or
  216. Vector, and presents the interface of each in a handy condensed form.
  217. It also covers I/O, graphics, networking, and development tools.
  218.  
  219. The book is handy to keep around for quick reference.  Thanks to Herb
  220. Weiner for the suggestion.
  221.  
  222.  
  223. JAVA PROGRAM PACKAGING PART 2 - PUBLIC/PRIVATE
  224.  
  225. In the last issue we talked about CLASSPATH and Java packages.  In
  226. this and subsequent issues, we'll be discussing visibility specifiers
  227. for instance (per object) and class (shared across all object
  228. instances) variables and methods.
  229.  
  230. The first two of these specifiers are "public" and "private".
  231. Specifying public means that the variable or method is accessible
  232. everywhere, and is inherited by any subclasses that extend from the
  233. class.  "Everywhere" means subclasses of the class in question and
  234. other classes in the same or other packages.  For example:
  235.  
  236.         // file A.java
  237.  
  238.         public class A {
  239.                 public void f() {}
  240.                 public static int x = 37;
  241.         }
  242.  
  243.         // file B.java
  244.  
  245.         public class B {
  246.                 public static void main(String args[])
  247.                 {
  248.                         A a = new A();
  249.                         a.f();          // calls public method
  250.                         A.x = -19;      // sets static variable in A
  251.                 }
  252.         }
  253.  
  254. By contrast, "private" means that no other class anywhere can access a
  255. method or variable.  For example:
  256.  
  257.         // file A.java
  258.  
  259.         public class A {
  260.                 private void f() {}
  261.                 private static int x = 37;
  262.         }
  263.  
  264.         // file B.java
  265.  
  266.         public class B {
  267.                 public static void main(String args[])
  268.                 {
  269.                         A a = new A();
  270.                         a.f();          // illegal
  271.                         A.x = -19;      // illegal
  272.                 }
  273.         }
  274.  
  275. Private instance variables are not inherited.  This means something
  276. slightly different in Java than in C++.  In both languages private
  277. data members are in fact part of any derived class, but in Java the
  278. term "not inherited" in reference to private variables does double
  279. duty to mean "not accessible".
  280.  
  281. One crude way of figuring out just how much space an object instance
  282. requires is to use a technique like this one, where the amount of free
  283. memory is saved, many object instances are allocated, and then a
  284. calculation is done to determine the number of bytes per object
  285. instance:
  286.  
  287.         class x1 {
  288.                 private double d1;
  289.                 private double d2;
  290.                 private double d3;
  291.                 private double d4;
  292.                 private double d5;
  293.         }
  294.  
  295.         public class x2 extends x1 {
  296.                 public static void main(String args[])
  297.                 {
  298.                         int N = 10000;
  299.                         x2 vec[] = new x2[N];
  300.  
  301.                         long start_mem = Runtime.getRuntime().freeMemory();
  302.  
  303.                         for (int i = 0; i < N; i++)
  304.                                 vec[i] = new x2();
  305.  
  306.                         long curr_mem = Runtime.getRuntime().freeMemory();
  307.  
  308.                         long m = (start_mem - curr_mem) / N;
  309.  
  310.                         System.out.println("memory used per object = " + m);
  311.                 }
  312.         }
  313.  
  314. This technique is not without its pitfalls (notably issues related to
  315. garbage collection), but sometimes can provide useful information
  316. about object sizes.
  317.  
  318. In future issues we will be talking about other kinds of visibility,
  319. such as the default visibility level and "protected".
  320.  
  321.  
  322. PERFORMANCE - STRING OPERATIONS
  323.  
  324. Java is a young language and it's hard to say for sure just how some
  325. of the performance aspects of the language will shake out.  But we
  326. will offer from time to time some performance tips that may be useful.
  327. Many performance techniques apply in any programming language.
  328.  
  329. Suppose that you want to create and print a list of numbers, like so:
  330.  
  331.         public class test1 {
  332.                 public static void main(String args[])
  333.                 {
  334.                         String s = "[";
  335.  
  336.                         for (int i = 1; i <= 2000; i++) {
  337.                                 if (i > 1)
  338.                                         s += ",";
  339.                                 s += Integer.toString(i, 10);
  340.                         }
  341.  
  342.                         s += "]";
  343.  
  344.                         System.out.println(s);
  345.                 }
  346.         }
  347.  
  348. This works OK but seems kind of slow.  It takes about 13 seconds using
  349. JDK 1.0 on a Pentium.  When we profile the program, we find that it
  350. seems to be doing lots of data shuffling and so forth, with the
  351. garbage collector called 40 times.
  352.  
  353. It turns out that using "+=" on Strings is quite expensive, and the
  354. reason is that Strings themselves are immutable, that is, are not
  355. changed after creation.  To append to a String you must copy out the
  356. String to a StringBuffer and append to it and then convert it back.
  357. StringBuffers are used for doing operations on Strings, like "+" and
  358. "+=".
  359.  
  360. This idea can be illustrated by the following example:
  361.  
  362.         public class test2 {
  363.                 public static void main(String args[])
  364.                 {
  365.                         String s = "aaa";       // sequence #1
  366.                         s += "bbb";
  367.  
  368.                         System.out.println(s);
  369.  
  370.                         String ss = "ccc";      // sequence #2
  371.                         StringBuffer sb = new StringBuffer();
  372.                         sb.append(ss);
  373.                         sb.append("ddd");
  374.                         String ss_save = ss;
  375.                         ss = sb.toString();
  376.  
  377.                         System.out.println(ss_save);
  378.                         System.out.println(ss);
  379.                 }
  380.         }
  381.  
  382. These two sequences are equivalent; using "+=" causes the processing
  383. shown in sequence #2 (except for the "ss_save" line).
  384.  
  385. Note that we captured the old value of ss before ss was changed to
  386. point to a new String.  The old String didn't change when we
  387. reassigned ss, we just changed a reference that pointed at it to point
  388. at a new String.
  389.  
  390. Going back to the original example, we can rewrite it as:
  391.  
  392.         public class test3 {
  393.                 public static void main(String args[])
  394.                 {
  395.                         StringBuffer sb = new StringBuffer();
  396.         
  397.                         sb.append("[");
  398.         
  399.                         for (int i = 1; i <= 2000; i++) {
  400.                                 if (i > 1)
  401.                                         sb.append(",");
  402.                                 sb.append(Integer.toString(i, 10));
  403.                         }
  404.  
  405.                         sb.append("]");
  406.  
  407.                         String s = sb.toString();
  408.  
  409.                         System.out.println(s);
  410.                 }
  411.         }
  412.  
  413. resulting in about a 6X speedup.
  414.  
  415. A useful tool for performance tuning is the Java profiler, which can
  416. help you find bottlenecks in your code.  Using JDK 1.0, one can say:
  417.  
  418.         $ javac test.java
  419.  
  420.         $ java -prof test
  421.  
  422. resulting in a file "java.prof" being written.  Lines of this file
  423. contain a count of the number of calls, the name of a called method,
  424. the name of the method doing the calling, and a time in milliseconds.
  425.  
  426. Using an Awk script such as that shown below, you can summarize this
  427. file into a form similar to prof(1) output for UNIX:
  428.  
  429.         100.0% time = 13.07 seconds
  430.          36.0    14895 java/lang/StringBuffer.ensureCapacity(I)V
  431.          30.9    18002 java/lang/System.arraycopy(Ljava/lang/Object; ...
  432.          15.4       40 java/lang/System.gc()V
  433.           3.0     2001 java/lang/Integer.toString(II)Ljava/lang/String;
  434.           2.8     8002 java/lang/StringBuffer.append(Ljava/lang/String ...
  435.           2.0        1 t2.main([Ljava/lang/String;)V
  436.           1.5     4001 java/lang/String.<init>(Ljava/lang/StringBuffer;)V
  437.           1.3     6893 java/lang/StringBuffer.append(C)Ljava/lang ...
  438.           1.3     6002 java/lang/StringBuffer.<init>(I)V
  439.  
  440. I was told by someone at Sun that the format of the java.prof file
  441. will change in a future JDK release, so be careful when using this
  442. script with such releases.
  443.  
  444.         #!/bin/sh
  445.         
  446.         awk '
  447.                 $1 == "#" && $2 == "count" {
  448.                         flag = 1;
  449.                         next;
  450.                 }
  451.                 $1 == "#" && $2 != "count" {
  452.                         flag = 0;
  453.                         next;
  454.                 }
  455.                 {
  456.                         if (flag) {
  457.                                 n++;
  458.                                 data[n,1] = $1;
  459.                                 data[n,2] = $2;
  460.                                 data[n,3] = $3;
  461.                                 data[n,4] = $4;
  462.                         }
  463.                 }
  464.                 END {
  465.                         for (i = 1; i <= n; i++) {
  466.                                 cnt[data[i,2]] += data[i,1];
  467.                                 tim[data[i,2]] += data[i,4];
  468.                         }
  469.                         for (i in tim) {
  470.                                 for (j = 1; j <= n; j++) {
  471.                                         if (i == data[j,3])
  472.                                                 tim[i] -= data[j,4];
  473.                                 }
  474.                                 total += tim[i];
  475.                         }
  476.                         printf "%5.1f%% time = %.2f seconds\n",
  477.                                 100.0, total / 1000.0;
  478.                         for (i in cnt) {
  479.                                 printf "%5.1f  %7ld %s\n",
  480.                                     tim[i] * 100.0 / total, cnt[i], i;
  481.                         }
  482.                 }
  483.         ' <java.prof | sort -rn
  484.         
  485.         exit 0
  486.  
  487.  
  488. ACKNOWLEDGEMENTS
  489.  
  490. Thanks to Thierry Ciot, Irv Kanode, Mike Paluka, and Alan Saldanha for
  491. help with proofreading.
  492.  
  493.  
  494. SUBSCRIPTION INFORMATION / BACK ISSUES
  495.  
  496. To subscribe to the newsletter, send mail to majordomo@world.std.com
  497. with this line as its message body:
  498.  
  499. subscribe java_letter
  500.  
  501. Back issues are available via FTP from:
  502.  
  503.         rmii.com /pub2/glenm/javalett
  504.  
  505. or on the Web at:
  506.  
  507.         http://www.rmii.com/~glenm
  508.  
  509. There is also a C++ newsletter.  To subscribe to it, say:
  510.  
  511. subscribe c_plus_plus
  512.  
  513. using the same majordomo@world.std.com address.
  514.  
  515. -------------------------
  516.  
  517. Copyright (c) 1996 Glen McCluskey.  All Rights Reserved.
  518.  
  519. This newsletter may be further distributed provided that it is copied
  520. in its entirety, including the newsletter number at the top and the
  521. copyright and contact information at the bottom.
  522.  
  523. Glen McCluskey & Associates
  524. Professional Computer Consulting
  525. Internet: glenm@glenmccl.com
  526. Phone: (800) 722-1613 or (970) 490-2462
  527. Fax: (970) 490-2463
  528. FTP: rmii.com /pub2/glenm/javalett (for back issues)
  529. Web: http://www.rmii.com/~glenm
  530.